#pragma once
#include "../common/net.hpp"
#include <set>
namespace BRpc
{
    namespace Server
    {
        class ProviderManager
        {
        public:
            using ptr = std::shared_ptr<ProviderManager>;
            // 描述提供者信息
            struct Provider
            {
                using ptr = std::shared_ptr<Provider>;
                std::mutex _mutex;
                Address _host;
                std::vector<std::string> _methods; // 提供的所有方法
                BaseConnection::ptr _conn;
                Provider(const BaseConnection::ptr &conn, const Address &host) : _conn(conn), _host(host) {}
                void appendMethod(const ::std::string method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.emplace_back(method);
                }
            };

        public:
            void addProvide(const BaseConnection::ptr &conn, const Address &host, const std::string &method)
            {
                Provider::ptr provider;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    // 搜寻注册者之前是否注册过,没注册过就添加进连接管理
                    auto it = _conns.find(conn);
                    if (it != _conns.end())
                        provider = it->second;
                    else
                    {
                        provider = std::make_shared<Provider>(conn, host);
                        _conns.insert(std::make_pair(conn, provider));
                    }
                    // 将方法插入提供者管理
                    auto &providers = _providers[method];
                    providers.insert(provider);
                }
                // 管理者添加自己可提供的方法
                provider->appendMethod(method);
            }
            // 当提供者下线时获取它的信息--用于广播
            Provider::ptr getProvider(const BaseConnection::ptr &conn)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _conns.find(conn);
                if (it == _conns.end())
                {
                    DLOG("这个连接不是一个提供者");
                    return Provider::ptr();
                }
                return it->second;
            }
            // 删除提供者
            void delProvider(const BaseConnection::ptr &conn)
            {
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it == _conns.end())
                    {
                        ILOG("这个连接不是一个提供者");
                        return;
                    }
                    // 将这个提供者所提供的方法的映射全部删除
                    for (auto &x : it->second->_methods)
                    {
                        auto &pro = _providers[x];
                        pro.erase(it->second);
                    }
                    // 将连接与提供的映射删除
                    _conns.erase(it);
                }
            }
            //获取这个方法所有提供者的地址信息
            std::vector<Address> methodHosts(const std::string& method)
            {
                auto it=_providers.find(method);
                if(it==_providers.end())
                {
                    return std::vector<Address>();
                }
                std::vector<Address> ret;
                
                for(auto& host:it->second)
                {
                    ret.push_back(host->_host);
                }
                return ret;
            }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string, std::set<Provider::ptr>> _providers; // 存储着哪些方法哪些提供者可以提供
            std::unordered_map<BaseConnection::ptr, Provider::ptr> _conns;       // 连接与提供者的映射关系
        };

        class DiscovererManager
        {
        public:
            using ptr = std::shared_ptr<DiscovererManager>;
            struct Discoverer
            {
                using ptr = std::shared_ptr<Discoverer>;
                std::mutex _mutex;
                BaseConnection::ptr _conn;         // 发现者关联的客户端连接
                std::vector<std::string> _methods; // 发现过的服务名称
                Discoverer(const BaseConnection::ptr &c) : _conn(c) {}
                void appendMethod(const std::string &method)
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    _methods.push_back(method);
                };
            };

        public:
            Discoverer::ptr addDiscoverer(const BaseConnection::ptr &conn, const std::string &method)
            {
                Discoverer::ptr discoverer;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    // 搜寻注册者之前是否注册过,没注册过就添加进连接管理
                    auto it = _conns.find(conn);
                    if (it != _conns.end())
                        discoverer = it->second;
                    else
                    {
                        discoverer = std::make_shared<Discoverer>(conn);
                        _conns.insert(std::make_pair(conn, discoverer));
                    }
                    // 将方法插入发现者管理
                    auto &discoverers = _discoverers[method];
                    discoverers.insert(discoverer);
                }
                // 发现者添加自己可发现的方法
                discoverer->appendMethod(method);
                return discoverer;
            }
            void delDiscoverer(const BaseConnection::ptr &conn)
            {
                 {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it = _conns.find(conn);
                    if (it == _conns.end())
                    {
                        ILOG("这个连接不是一个发现者");
                        return;
                    }
                    // 将这个发现者所发现的方法的映射全部删除
                    for (auto &x : it->second->_methods)
                    {
                        auto &pro = _discoverers[x];
                        pro.erase(it->second);
                    }
                    // 将连接与发现的映射删除
                    _conns.erase(it);
                }
            }
            void onlineNotify(const std::string &method, const Address &host)
            {
                notify(method,host,ServiceOptype::SERVICE_ONLINE);
            }
            void offlineNotify(const std::string &method, const Address &host) 
            {
                notify(method,host,ServiceOptype::SERVICE_OFFLINE);
            }
        private:
             void notify(const std::string &method, const Address &host,const ServiceOptype& op) //在枚举这里加个const& 不知道会不会出问题
             {
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    auto it=_discoverers.find(method);
                    if(it==_discoverers.end())
                    {
                        ILOG("现在还没有人发现了这个方法");
                        return;
                    }
                    ServiceRequest::ptr msg_req = MessageFactory::create<ServiceRequest>();
                    msg_req->setId(UUID::uuid());
                    msg_req->setMType(MType::REQ_SERVICE);
                    msg_req->setOptype(op);
                    msg_req->setHost(host);
                    msg_req->setMethod(method);
                    for(auto&x:it->second)
                    {
                        x->_conn->send(msg_req);
                    }
                    
                }
             }
        private:
            std::mutex _mutex;
            std::unordered_map<std::string, std::set<Discoverer::ptr>> _discoverers;
            std::unordered_map<BaseConnection::ptr, Discoverer::ptr> _conns;
        };

        class PDManager
        {
        public:
            using ptr = std::shared_ptr<PDManager>;
        public:
            PDManager() : _providers(std::make_shared<ProviderManager>()),
                          _discoverers(std::make_shared<DiscovererManager>())
            {
            }
            void onServiceRequest(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) 
            {
                auto service_type=msg->optype();
                //服务注册
                if(service_type==ServiceOptype::SERVICE_REGISTRY)
                {
                    //先将服务放进提供者管理
                    _providers->addProvide(conn,msg->host(),msg->method());
                    ILOG("%s:%d提供了%s方法",msg->host().first.c_str(),msg->host().second,msg->method().c_str());
                    //提醒注册了这个方法的发现者
                    _discoverers->onlineNotify(msg->method(),msg->host());
                    return registerResponse(conn,msg);
                }
                //服务发现
                else if(service_type==ServiceOptype::SERVICE_DISCOVERY)
                {
                    //将发现放进发现者管理
                    _discoverers->addDiscoverer(conn,msg->method());
                    return discoverResponse(conn,msg);
                }
                //错误的服务请求
                else
                {
                    ELOG("收到了服务请求,但类型不对");
                    return errorResponse(conn,msg);
                }
            }
            void onConnShutdown(const BaseConnection::ptr &conn)
            {
                auto provider=_providers->getProvider(conn);
                
                if(provider.get()!=nullptr)
                {
                    //先对发现了提供者提供的方法的发现者进行消息广播
                    ILOG("%s:%d下线了",provider->_host.first.c_str(),provider->_host.second);
                    for(auto&method:provider->_methods)
                    {
                        ILOG("它提供的%s方法下线",method.c_str());
                        _discoverers->offlineNotify(method,provider->_host);
                    }
                    //解除提供者管理
                    _providers->delProvider(conn);
                    
                }
                //无论如何都会走下来 就算这个连接是一个提供者也没事 因为如果是提供者的话 发现者的删除会直接出去
                _discoverers->delDiscoverer(conn);
            }
        private:
            void errorResponse(const BaseConnection::ptr &conn, const ServiceRequest::ptr &msg) {
                    auto msg_rsp = MessageFactory::create<ServiceResponse>();
                    msg_rsp->setId(msg->id());
                    msg_rsp->setMType(MType::RSP_SERVICE);
                    msg_rsp->setRCode(RCode::RCODE_INVALID_OPTYPE);
                    msg_rsp->setOptype(ServiceOptype::SERVICE_UNKNOW);
                    conn->send(msg_rsp);
                }
            void registerResponse(const BaseConnection::ptr& conn,const ServiceRequest::ptr& req)
            {
                auto ser_rsp=MessageFactory::create<ServiceResponse>();
                ser_rsp->setId(req->id());
                ser_rsp->setMType(MType::RSP_SERVICE);
                ser_rsp->setOptype(ServiceOptype::SERVICE_REGISTRY);
                ser_rsp->setRCode(RCode::RCODE_OK);
                conn->send(ser_rsp);
            }
            void discoverResponse(const BaseConnection::ptr& conn,const ServiceRequest::ptr& req)
            {
                std::vector<Address> hosts=_providers->methodHosts(req->method());
                auto ser_rsp=MessageFactory::create<ServiceResponse>();
                ser_rsp->setId(req->id()); //id需要与请求保持一致 因为客户端的requestor需要根据id来处理接收到的应答
                ser_rsp->setMType(MType::RSP_SERVICE);
                ser_rsp->setOptype(ServiceOptype::SERVICE_REGISTRY);
                if(hosts.empty())   //服务没有提供者
                {
                    ser_rsp->setRCode(RCode::RCODE_NOT_FOUND_SERVICE);
                    return conn->send(ser_rsp);
                }
                ser_rsp->setRCode(RCode::RCODE_OK);
                ser_rsp->setHost(hosts);
                ser_rsp->setMethod(req->method());
                conn->send(ser_rsp);
            }
        private:
            ProviderManager::ptr _providers;
            DiscovererManager::ptr _discoverers;
        };
    }
}